home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 May: Tool Chest / Developer CD Series May 1996 (Tool Chest) (Apple Computer) (1996).iso / Tool Chest / Development Tools & Languages / • Other Platforms / PCCTS 1.31 / antlr / antlr.g < prev    next >
Encoding:
Text File  |  1995-03-10  |  44.8 KB  |  1,578 lines  |  [TEXT/MPS ]

  1. /*
  2.  * antlr.g    --    PCCTS Version 1.xx ANTLR
  3.  *
  4.  * $Id: antlr.g,v 1.15 1994/12/31 21:02:55 parrt Exp parrt $
  5.  * $Revision: 1.15 $
  6.  *
  7.  * Parse an antlr input grammar and build a syntax-diagram.
  8.  *
  9.  * Written in itself (needs at least 1.06 to work)
  10.  *
  11.  * SOFTWARE RIGHTS
  12.  *
  13.  * We reserve no LEGAL rights to the Purdue Compiler Construction Tool
  14.  * Set (PCCTS) -- PCCTS is in the public domain.  An individual or
  15.  * company may do whatever they wish with source code distributed with
  16.  * PCCTS or the code generated by PCCTS, including the incorporation of
  17.  * PCCTS, or its output, into commerical software.
  18.  *
  19.  * We encourage users to develop software with PCCTS.  However, we do ask
  20.  * that credit is given to us for developing PCCTS.  By "credit",
  21.  * we mean that if you incorporate our source code into one of your
  22.  * programs (commercial product, research project, or otherwise) that you
  23.  * acknowledge this fact somewhere in the documentation, research report,
  24.  * etc...  If you like PCCTS and have developed a nice tool with the
  25.  * output, please mention that you developed it using PCCTS.  In
  26.  * addition, we ask that this header remain intact in our source code.
  27.  * As long as these guidelines are kept, we expect to continue enhancing
  28.  * this system and expect to make other tools available as they are
  29.  * completed.
  30.  *
  31.  * ANTLR 1.31
  32.  * Terence Parr
  33.  * Parr Research Corporation
  34.  * with Purdue University and AHPCRC, University of Minnesota
  35.  * 1989-1995
  36.  */
  37. #header <<
  38.     #ifdef __cplusplus
  39.     #ifndef __STDC__
  40.     #define __STDC__
  41.     #endif
  42.     #endif
  43.     #include "set.h"
  44.     #include <ctype.h>
  45.     #include "syn.h"
  46.     #include "hash.h"
  47.     #include "generic.h"
  48.     #define zzcr_attr(attr,tok,t)
  49.     >>
  50.  
  51. <<
  52. #ifdef __STDC__
  53. static void chkToken(char *, char *, char *, int);
  54. #else
  55. static void chkToken();
  56. #endif
  57.  
  58. static int class_nest_level = 0;
  59. extern int inAlt;
  60. extern set attribsRefdFromAction;
  61. extern int UsedOldStyleAttrib;
  62. extern int UsedNewStyleLabel;
  63. >>
  64.  
  65. #lexaction <<
  66. /* maintained, but not used for now */
  67. set AST_nodes_refd_in_actions = set_init;
  68. int inAlt = 0;
  69. set attribsRefdFromAction;
  70. int UsedOldStyleAttrib = 0;
  71. int UsedNewStyleLabel = 0;
  72. >>
  73.  
  74. #lexclass STRINGS
  75. #token QuotedTerm "\""        << zzmode(START); >>
  76. #token "\n"                    <<
  77.                             zzline++;
  78.                             warn("eoln found in string");
  79.                             zzskip();
  80.                             >>
  81. #token "\\\n"                << zzline++; zzmore(); >>
  82. #token "\\~[]"                << zzmore(); >>
  83. #token "~[\n\"\\]+"            << zzmore(); >>
  84.  
  85. #lexclass ACTION_STRINGS
  86. #token "\""                    << zzmode(ACTIONS); zzmore(); >>
  87. #token "\n"                    <<
  88.                             zzline++;
  89.                             warn("eoln found in string (in user action)");
  90.                             zzskip();
  91.                             >>
  92. #token "\\\n"                << zzline++; zzmore(); >>
  93. #token "\\~[]"                << zzmore(); >>
  94. #token "~[\n\"\\]+"            << zzmore(); >>
  95.  
  96. #lexclass ACTION_CHARS
  97. #token "'"                    << zzmode(ACTIONS); zzmore(); >>
  98. #token "\n"                    <<
  99.                             zzline++;
  100.                             warn("eoln found in char literal (in user action)");
  101.                             zzskip();
  102.                             >>
  103. #token "\\~[]"                << zzmore(); >>
  104. #token "~[\n'\\]+"            << zzmore(); >>
  105.  
  106. #lexclass ACTION_COMMENTS
  107. #token "\*/"                << zzmode(ACTIONS); zzmore(); >>
  108. #token "\*"                    << zzmore(); >>
  109. #token "\n"                    << zzline++; zzmore(); DAWDLE; >>
  110. #token "~[\n\*]+"            << zzmore(); >>
  111.  
  112. #lexclass TOK_DEF_COMMENTS
  113. #token "\*/"                << zzmode(PARSE_ENUM_FILE);  
  114. zzmore(); >>
  115. #token "\*"                    << zzmore(); >>
  116. #token "\n"                    << zzline++; zzmore(); DAWDLE; >>
  117. #token "~[\n\*]+"            << zzmore(); >>
  118.  
  119. #lexclass TOK_DEF_CPP_COMMENTS
  120. #token "\n"                    << zzline++; zzmode(PARSE_ENUM_FILE); zzskip(); DAWDLE; >>
  121. #token "~[\n]+"                << zzskip(); >>
  122.  
  123. #lexclass ACTION_CPP_COMMENTS
  124. #token "\n"                    << zzline++; zzmode(ACTIONS); zzmore(); DAWDLE; >>
  125. #token "~[\n]+"                << zzmore(); >>
  126.  
  127. #lexclass CPP_COMMENTS
  128. #token "\n"                    << zzline++; zzmode(START); zzskip(); DAWDLE; >>
  129. #token "~[\n]+"                << zzskip(); >>
  130.  
  131. #lexclass COMMENTS
  132. #token "\*/"                << zzmode(START); zzskip(); >>
  133. #token "\*"                    << zzskip(); >>
  134. #token "\n"                    << zzline++; zzskip(); DAWDLE; >>
  135. #token "~[\n\*]+"            << zzskip(); >>
  136.  
  137. /*
  138.  * This lexical class accepts actions of type [..] and <<..>>
  139.  *
  140.  * It translates the following special items for C:
  141.  *
  142.  * $j        --> "zzaArg(current zztasp, j)"
  143.  * $i.j        --> "zzaArg(zztaspi, j)"
  144.  * $i.nondigit> "zzaArg(current zztasp, i).nondigit"
  145.  * $$        --> "zzaRet"
  146.  * $alnum    --> "alnum"            (used to ref parameters)
  147.  * $rule    --> "zzaRet"
  148.  * $retval    --> "_retv.retval" if > 1 return values else "_retv"
  149.  * $[token, text] --> "zzconstr_attr(token, text)"
  150.  * $[]        --> "zzempty_attr()"
  151.  *
  152.  * It translates the following special items for C++:
  153.  * (attributes are now stored with 'Token' and $i's are only
  154.  *  pointers to the Tokens.  Rules don't have attributes now.)
  155.  *
  156.  * $j        --> "_tbj" where b is the block level
  157.  * $i.j        --> "_tij"
  158.  * $j->nondigit> "_tbj->nondigit"
  159.  * $$        --> "$$"
  160.  * $alnum    --> "alnum"            (used to ref parameters)
  161.  * $rule    --> "$rule"
  162.  * $retval    --> "_retv.retval" if > 1 return values else "_retv"
  163.  * $[token, text] --> invalid
  164.  * $[]        --> invalid
  165.  *
  166.  * And, for trees:
  167.  *
  168.  * #0        -->    "(*_root)"
  169.  * #i        --> "zzastArg(i)"
  170.  * #[args]    --> "zzmk_ast(zzastnew(), args)"
  171.  * #[]        --> "zzastnew()"
  172.  * #( root, child1, ..., childn )
  173.  *            --> "zztmake(root, child1, ...., childn, NULL)"
  174.  * #()        --> "NULL"
  175.  *
  176.  * For C++, ...
  177.  *
  178.  * #0        -->    "(*_root)"
  179.  * #i        --> "_astbi" where b is the block level
  180.  * #alnum    --> "alnum_ast"    (used to ref #label)
  181.  * #[args]    --> "new AST(args)"
  182.  * #[]        --> "new AST"
  183.  * #( root, child1, ..., childn )
  184.  *            --> "AST::tmake(root, child1, ...., childn, NULL)"
  185.  * #()        --> "NULL"
  186.  *
  187.  * To escape,
  188.  *
  189.  * \]        --> ]
  190.  * \)        --> )
  191.  * \$        --> $
  192.  * \#        --> #
  193.  *
  194.  * A stack is used to nest action terminators because they can be nested
  195.  * like crazy:  << #[$[..],..] >>
  196.  */
  197. #lexclass ACTIONS
  198. #token Action "\>\>"        << /* these do not nest */
  199.                               zzmode(START);
  200.                               NLATEXT[0] = ' ';
  201.                               NLATEXT[1] = ' ';
  202.                               zzbegexpr[0] = ' ';
  203.                               zzbegexpr[1] = ' ';
  204.                               if ( zzbufovf ) {
  205.                                 err( eMsgd("action buffer overflow; size %d",ZZLEXBUFSIZE));
  206.                               }
  207.                             >>
  208. #token Pred "\>\>?"            << /* these do not nest */
  209.                               zzmode(START);
  210.                               NLATEXT[0] = ' ';
  211.                               NLATEXT[1] = ' ';
  212.                               zzbegexpr[0] = '\0';
  213.                               if ( zzbufovf ) {
  214.                                 err( eMsgd("predicate buffer overflow; size %d",ZZLEXBUFSIZE));
  215.                               }
  216.                             >>
  217. #token PassAction "\]"        << if ( topint() == ']' ) {
  218.                                   popint();
  219.                                   if ( istackempty() )    /* terminate action */
  220.                                   {
  221.                                       zzmode(START);
  222.                                       NLATEXT[0] = ' ';
  223.                                       zzbegexpr[0] = ' ';
  224.                                       if ( zzbufovf ) {
  225.                                         err( eMsgd("parameter buffer overflow; size %d",ZZLEXBUFSIZE));
  226.                                       }
  227.                                   }
  228.                                   else {
  229.                                       /* terminate $[..] and #[..] */
  230.                                       if ( GenCC ) zzreplstr("))");
  231.                                       else zzreplstr(")");
  232.                                       zzmore();
  233.                                   }
  234.                                }
  235.                                else if ( topint() == '|' ) { /* end of simple [...] */
  236.                                   popint();
  237.                                   zzmore();
  238.                                }
  239.                                else zzmore();
  240.                             >>
  241. #token "\n"                    << zzline++; zzmore(); DAWDLE; >>
  242. #token "\>"                    << zzmore(); >>
  243. #token "$"                    << zzmore(); >>
  244. #token "$$"                    << if ( !GenCC ) {zzreplstr("zzaRet"); zzmore();}
  245.                                else err("$$ use invalid in C++ mode"); >>
  246.  
  247. #token "$\[\]"                << if ( !GenCC ) {zzreplstr("zzempty_attr"); zzmore();}
  248.                                else err("$[] use invalid in C++ mode"); >>
  249. #token "$\["                <<
  250.                             pushint(']');
  251.                             if ( !GenCC ) zzreplstr("zzconstr_attr(");
  252.                             else err("$[..] use invalid in C++ mode");
  253.                             zzmore();
  254.                             >>
  255. #token "$[0-9]+"            <<{
  256.                             static char buf[100];
  257.                             if ( strlen(zzbegexpr)>85 )
  258.                                 fatal("$i attrib ref too big");
  259.                             set_orel(atoi(zzbegexpr+1), &attribsRefdFromAction);
  260.                             if ( !GenCC ) sprintf(buf,"zzaArg(zztasp%d,%s)",
  261.                                         BlkLevel-1,zzbegexpr+1);
  262.                             else sprintf(buf,"_t%d%s",
  263.                                         BlkLevel-1,zzbegexpr+1);
  264.                             zzreplstr(buf);
  265.                             zzmore();
  266.                             UsedOldStyleAttrib = 1;
  267.                             if ( UsedNewStyleLabel )
  268.                                 err("cannot mix old-style $i with new-style labels");
  269.                             }
  270.                             >>
  271. #token "$[0-9]+."            <<{
  272.                             static char buf[100];
  273.                             if ( strlen(zzbegexpr)>85 )
  274.                                 fatal("$i.field attrib ref too big");
  275.                             zzbegexpr[strlen(zzbegexpr)-1] = ' ';
  276.                             set_orel(atoi(zzbegexpr+1), &attribsRefdFromAction);
  277.                             if ( !GenCC ) sprintf(buf,"zzaArg(zztasp%d,%s).",
  278.                                         BlkLevel-1,zzbegexpr+1);
  279.                             else sprintf(buf,"_t%d%s.",
  280.                                         BlkLevel-1,zzbegexpr+1);
  281.                             zzreplstr(buf);
  282.                             zzmore();
  283.                             UsedOldStyleAttrib = 1;
  284.                             if ( UsedNewStyleLabel )
  285.                                 err("cannot mix old-style $i with new-style labels");
  286.                             }
  287.                             >>
  288. #token "$[0-9]+.[0-9]+"        <<{
  289.                             static char buf[100];
  290.                             static char i[20], j[20];
  291.                             char *p,*q;
  292.                             if (strlen(zzbegexpr)>85) fatal("$i.j attrib ref too big");
  293.                             for (p=zzbegexpr+1,q= &i[0]; *p!='.'; p++) {
  294.                                 if ( q == &i[20] )
  295.                                      fatalFL("i of $i.j attrib ref too big",
  296.                                              FileStr[CurFile], zzline );
  297.                                 *q++ = *p;
  298.                             }
  299.                             *q = '\0';
  300.                             for (p++, q= &j[0]; *p!='\0'; p++) {
  301.                                 if ( q == &j[20] )
  302.                                     fatalFL("j of $i.j attrib ref too big",
  303.                                             FileStr[CurFile], zzline );
  304.                                 *q++ = *p;
  305.                             }
  306.                             *q = '\0';
  307.                             if ( !GenCC ) sprintf(buf,"zzaArg(zztasp%s,%s)",i,j);
  308.                             else sprintf(buf,"_t%s%s",i,j);
  309.                             zzreplstr(buf);
  310.                             zzmore();
  311.                             UsedOldStyleAttrib = 1;
  312.                             if ( UsedNewStyleLabel )
  313.                                 err("cannot mix old-style $i with new-style labels");
  314.                             }
  315.                             >>
  316. #token "$[_a-zA-Z][_a-zA-Z0-9]*"
  317.                             <<{ static char buf[300];
  318.                             zzbegexpr[0] = ' ';
  319.                             if ( CurRule != NULL &&
  320.                                  strcmp(CurRule, &zzbegexpr[1])==0 ) {
  321.                                 if ( !GenCC ) zzreplstr("zzaRet");
  322.                             }
  323.                             else if ( CurRetDef != NULL &&
  324.                                       strmember(CurRetDef, &zzbegexpr[1])) {
  325.                                  if ( HasComma( CurRetDef ) ) {
  326.                                     require (strlen(zzbegexpr)<=285,
  327.                                              "$retval attrib ref too big");
  328.                                     sprintf(buf,"_retv.%s",&zzbegexpr[1]);
  329.                                     zzreplstr(buf);
  330.                                 }
  331.                                 else zzreplstr("_retv");
  332.                             }
  333.                             else if ( CurParmDef != NULL &&
  334.                                       strmember(CurParmDef, &zzbegexpr[1])) {
  335.                                 ;
  336.                             }
  337.                             else if ( hash_get(Elabel, &zzbegexpr[1])!=NULL ) {
  338.                                 ;
  339.                             }
  340.                             else
  341.                                 warn(eMsg1("$%s not parameter, return value, or element label",&zzbegexpr[1]));
  342.                             }
  343.                             zzmore();
  344.                             >>
  345. #token "#0"                    << zzreplstr("(*_root)"); zzmore(); >>
  346. #token "#\[\]"                << if ( GenCC ) zzreplstr("(new AST)");
  347.                                zzreplstr("zzastnew()"); zzmore();>>
  348. #token "#\(\)"                << zzreplstr("NULL"); zzmore(); >>
  349. #token "#[0-9]+"            <<{
  350.                             static char buf[100];
  351.                             if ( strlen(zzbegexpr)>85 )
  352.                                 fatal("#i AST ref too big");
  353.                             if ( GenCC ) sprintf(buf,"_ast%d%s",BlkLevel-1,zzbegexpr+1);
  354.                             else sprintf(buf,"zzastArg(%s)",zzbegexpr+1);
  355.                             zzreplstr(buf);
  356.                             zzmore();
  357.                             set_orel(atoi(zzbegexpr+1), &AST_nodes_refd_in_actions);
  358.                             }
  359.                             >>
  360. #token "#[_a-zA-Z][_a-zA-Z0-9]*"
  361.                             <<
  362.                             if ( !(strcmp(zzbegexpr, "#ifdef")==0 ||
  363.                                  strcmp(zzbegexpr, "#if")==0 ||
  364.                                  strcmp(zzbegexpr, "#else")==0 ||
  365.                                  strcmp(zzbegexpr, "#endif")==0 ||
  366.                                  strcmp(zzbegexpr, "#ifndef")==0 ||
  367.                                  strcmp(zzbegexpr, "#define")==0 ||
  368.                                  strcmp(zzbegexpr, "#pragma")==0 ||
  369.                                  strcmp(zzbegexpr, "#undef")==0 ||
  370.                                  strcmp(zzbegexpr, "#import")==0 ||
  371.                                  strcmp(zzbegexpr, "#line")==0 ||
  372.                                  strcmp(zzbegexpr, "#include")==0 ||
  373.                                  strcmp(zzbegexpr, "#error")==0) )
  374.                             {
  375.                                 static char buf[100];
  376.                                 sprintf(buf, "%s_ast", zzbegexpr+1);
  377.                                 zzreplstr(buf);
  378.                             }
  379.                             zzmore();
  380.                             >>
  381. #token "#\["                <<
  382.                             pushint(']');
  383.                             if ( GenCC ) zzreplstr("(new AST(");
  384.                             else zzreplstr("zzmk_ast(zzastnew(),");
  385.                             zzmore();
  386.                             >>
  387. #token "#\("                <<
  388.                             pushint('}');
  389.                             if ( GenCC ) zzreplstr("ASTBase::tmake(");
  390.                             else zzreplstr("zztmake(");
  391.                             zzmore();
  392.                             >>
  393. #token "#"                    << zzmore(); >>
  394. #token "\)"                    <<
  395.                             if ( istackempty() )
  396.                                 zzmore();
  397.                             else if ( topint()==')' ) {
  398.                                 popint();
  399.                             }
  400.                             else if ( topint()=='}' ) {
  401.                                 popint();
  402.                                 /* terminate #(..) */
  403.                                 zzreplstr(", NULL)");
  404.                             }
  405.                             zzmore();
  406.                             >>
  407. #token "\["                    <<
  408.                             pushint('|');    /* look for '|' to terminate simple [...] */
  409.                             zzmore();
  410.                             >>
  411. #token "\("                    <<
  412.                             pushint(')');
  413.                             zzmore();
  414.                             >>
  415.  
  416. #token "\\\]"                << zzreplstr("]");  zzmore(); >>
  417. #token "\\\)"                << zzreplstr(")");  zzmore(); >>
  418. #token "\\>"                << zzreplstr(">");  zzmore(); >>
  419.  
  420.  
  421. #token "'"                    << zzmode(ACTION_CHARS); zzmore();>>
  422. #token "\""                    << zzmode(ACTION_STRINGS); zzmore();>>
  423. #token "\\$"                << zzreplstr("$");  zzmore(); >>
  424. #token "\\#"                << zzreplstr("#");  zzmore(); >>
  425. #token "\\\n"                << zzline++; zzmore(); >>
  426. #token "\\~[\]\)>$#]"        << zzmore(); >> /* escaped char, always ignore */
  427. #token "/"                    << zzmore(); >>
  428. #token "/\*"                << zzmode(ACTION_COMMENTS); zzmore(); >>
  429. #token "\*/"                << warn("Missing /*; found dangling */ in action"); zzmore(); >>
  430. #token "//"                    << zzmode(ACTION_CPP_COMMENTS); zzmore(); >>
  431. #token "~[\n\)\(\\$#\>\]\[\"'/]+" << zzmore(); >>
  432.  
  433. #lexclass START
  434. #token "[\t\ ]+"            << zzskip(); >>                /* Ignore White */
  435. #token "[\n\r]"                << zzline++; zzskip(); >>    /* Track Line # */
  436. #token "\["                 << zzmode(ACTIONS); zzmore();
  437.                                istackreset();
  438.                                pushint(']'); >>
  439. #token "\<\<"               << action_file=CurFile; action_line=zzline;
  440.                                zzmode(ACTIONS); zzmore();
  441.                                istackreset();
  442.                                pushint('>'); >>
  443. #token "\""                    << zzmode(STRINGS); zzmore(); >>
  444. #token "/\*"                << zzmode(COMMENTS); zzskip(); >>
  445. #token "\*/"                << warn("Missing /*; found dangling */"); zzskip(); >>
  446. #token "//"                    << zzmode(CPP_COMMENTS); zzskip(); >>
  447. #token "\>\>"                << warn("Missing <<; found dangling \\>\\>"); zzskip(); >>
  448. #token WildCard "."
  449. #token "\@"                    <<FoundException = 1;>>
  450. #token Eof                    "@"
  451.                             <<    /* L o o k  F o r  A n o t h e r  F i l e */
  452.                             {
  453.                             FILE *new_input;
  454.                             new_input = NextFile();
  455.                             if ( new_input == NULL ) { NLA=Eof; return; }
  456.                             fclose( input );
  457.                             input = new_input;
  458.                             zzrdstream( input );
  459.                             zzskip();    /* Skip the Eof (@) char i.e continue */
  460.                             }
  461.                             >>
  462.  
  463. #token LABEL
  464.  
  465. #errclass "grammar-element" { element }
  466. #errclass "meta-symbol"        { "\}" "!" ";" "\|" "\~" "^" "\)" }
  467.  
  468. /*
  469.  * Get a grammar -- Build a list of rules like:
  470.  *
  471.  *    o-->Rule1--o
  472.  *    |
  473.  *    o-->Rule2--o
  474.  *    |
  475.  *    ...
  476.  *    |
  477.  *    o-->RuleN--o
  478.  */
  479. grammar :    <<Graph g;>>
  480.             (    "#header" Action
  481.                 <<
  482.                 if ( HdrAction==NULL ) {
  483.                 HdrAction = (char *) calloc(strlen(LATEXT(1))+1, sizeof(char));
  484.                 require(HdrAction!=NULL, "rule grammar: cannot allocate header action");
  485.                 strcpy(HdrAction, LATEXT(1));
  486.                 }
  487.                 else warn("additional #header statement ignored");
  488.                 >>
  489.             |    "#parser" QuotedTerm
  490.                 <<
  491.                 if ( GenCC ) {
  492.                     warn("#parser meta-op incompatible with -CC; ignored");
  493.                 }
  494.                 else {
  495.                     if ( strcmp(ParserName,"zzparser")==0 ) {
  496.                         ParserName=StripQuotes(mystrdup(LATEXT(1)));
  497.                         if ( RulePrefix[0]!='\0' )
  498.                         {
  499.                             warn("#parser meta-op incompatible with '-gp prefix'; '-gp' ignored");
  500.                             RulePrefix[0]='\0';
  501.                         }
  502.                     }
  503.                     else warn("additional #parser statement ignored");
  504.                 }
  505.                 >>
  506.             |    "#tokdefs" QuotedTerm
  507.                 <<{
  508.                 char *fname;
  509.                 zzantlr_state st; FILE *f; struct zzdlg_state dst;
  510.                 UserTokenDefsFile = mystrdup(LATEXT(1));
  511.                 zzsave_antlr_state(&st);
  512.                 zzsave_dlg_state(&dst);
  513.                 fname = mystrdup(LATEXT(1));
  514.                 f = fopen(StripQuotes(fname), "r");
  515.                 if ( f==NULL ) {warn(eMsg1("cannot open token defs file '%s'", fname+1));}
  516.                 else {
  517.                     ANTLRm(enum_file(fname+1), f, PARSE_ENUM_FILE);
  518.                     UserDefdTokens = 1;
  519.                 }
  520.                 zzrestore_antlr_state(&st);
  521.                 zzrestore_dlg_state(&dst);
  522.                 }>>
  523.             )*
  524.             (    Action
  525.                 <<{
  526.                 UserAction *ua = newUserAction(LATEXT(1));
  527.                 ua->file = action_file; ua->line = action_line;
  528.                 if ( class_nest_level>0 ) list_add(&class_actions, ua);
  529.                 else list_add(&BeforeActions, ua);
  530.                 }>>
  531.             |    laction
  532.             |    aLexclass
  533.             |    token
  534.             |    error
  535.             |    tclass
  536.             |    default_exception_handler
  537.             |    class_def
  538.             |    "\}"
  539.                 <<
  540.                 if ( class_nest_level==0 )
  541.                     warn("missing class definition for trailing '}'");
  542.                 class_nest_level--;
  543.                 >>
  544.             )*
  545.             rule        <<g=$3; SynDiag = (Junction *) $3.left;>>
  546.             (    rule    <<if ( $1.left!=NULL ) {g.right = NULL; g = Or(g, $1);}>>
  547.             |    aLexclass
  548.             |    token
  549.             |    error
  550.             |    tclass
  551.             |    class_def
  552.             |    "\}"
  553.                 <<
  554.                 if ( class_nest_level==0 )
  555.                     warn("missing class definition for trailing '}'");
  556.                 class_nest_level--;
  557.                 >>
  558.             )*
  559.             (    Action
  560.                 <<{
  561.                 UserAction *ua = newUserAction(LATEXT(1));
  562.                 ua->file = action_file; ua->line = action_line;
  563.                 if ( class_nest_level>0 ) list_add(&class_actions, ua);
  564.                 else list_add(&AfterActions, ua);
  565.                 }>>
  566.             |    laction
  567.             |    error
  568.             |    tclass
  569.             |    class_def
  570.             |    "\}"
  571.                 <<
  572.                 if ( class_nest_level==0 )
  573.                     warn("missing class definition for trailing '}'");
  574.                 class_nest_level--;
  575.                 >>
  576.             )*
  577.             Eof
  578.         ;
  579.         <<CannotContinue=TRUE;>>
  580.  
  581. class_def
  582.     :    <<int go=1; char name[MaxRuleName+1];>>
  583.         "class"
  584.         (    NonTerminal        <<if(go) strncpy(name,LATEXT(1),MaxRuleName);>>
  585.         |    TokenTerm        <<if(go) strncpy(name,LATEXT(1),MaxRuleName);>>
  586.         )
  587.         <<
  588.         if ( CurrentClassName[0]!='\0' && strcmp(CurrentClassName,name)!=0
  589.              && GenCC ) {
  590.             err("only one grammar class allowed in this release");
  591.             go = 0;
  592.         }
  593.         else strcpy(CurrentClassName, name);
  594.         >>
  595.         <<if ( !GenCC ) { err("class meta-op used without C++ option"); }>>
  596.         "\{"
  597.         <<
  598.         no_classes_found = 0;
  599.         if ( class_nest_level>=1 ) {warn("cannot have nested classes");}
  600.         else class_nest_level++;
  601.         >>
  602.     ;
  603.     <<CannotContinue=TRUE;>>
  604.  
  605. /*
  606.  * Build -o-->o-R-o-->o-    where -o-R-o- is the block from rule 'block'.
  607.  * Construct the RuleBlk front and EndRule node on the end of the
  608.  * block.  This is used to add FOLLOW pointers to the rule end.  Add the
  609.  * new rule name to the Rname hash table and sets its rulenum.
  610.  * Store the parameter definitions if any are found.
  611.  *
  612.  * Note that locks are required on the RuleBlk and EndRule nodes to thwart
  613.  * infinite recursion.
  614.  *
  615.  * Return the left graph pointer == NULL to indicate error/dupl rule def.
  616.  */
  617. rule    :    <<
  618.             ListNode *ex_groups = NULL;
  619.             ExceptionGroup *eg;
  620.             RuleEntry *q; Junction *p; Graph r; int f, l; ECnode *e;
  621.             set toksrefd, rulesrefd;
  622.             char *pdecl=NULL, *ret=NULL, *a; CurRetDef = CurParmDef = NULL;
  623.             CurExGroups = NULL;
  624.             CurElementLabels = NULL;
  625.             /* We want a new element label hash table for each rule */
  626.             if ( Elabel!=NULL ) killHashTable(Elabel);
  627.             Elabel = newHashTable();
  628.             attribsRefdFromAction = empty;
  629.             >>
  630.             NonTerminal
  631.             <<q=NULL;
  632.               if ( hash_get(Rname, LATEXT(1))!=NULL ) {
  633.                   err(eMsg1("duplicate rule definition: '%s'",LATEXT(1)));
  634.                   CannotContinue=TRUE;
  635.               }
  636.               else
  637.               {
  638.                     q = (RuleEntry *)hash_add(Rname,
  639.                                             LATEXT(1),
  640.                                             (Entry *)newRuleEntry(LATEXT(1)));
  641.                   CurRule = q->str;
  642.               }
  643.               CurRuleNode = q;
  644.               f = CurFile; l = zzline;
  645.               NumRules++;
  646.             >>
  647.             {    "!"  <<if ( q!=NULL ) q->noAST = TRUE;>> }
  648.             {    <<;>>
  649.                 {"\<"}
  650.                 PassAction
  651.                 <<    pdecl = (char *) calloc(strlen(LATEXT(1))+1, sizeof(char));
  652.                     require(pdecl!=NULL, "rule rule: cannot allocate param decl");
  653.                     strcpy(pdecl, LATEXT(1));
  654.                     CurParmDef = pdecl;
  655.                 >>
  656.             }
  657.             {    "\>"
  658.                 PassAction
  659.                 <<    ret = (char *) calloc(strlen(LATEXT(1))+1, sizeof(char));
  660.                     require(ret!=NULL, "rule rule: cannot allocate ret type");
  661.                     strcpy(ret, LATEXT(1));
  662.                      CurRetDef = ret;
  663.                 >>
  664.             }
  665.             { QuotedTerm <<if ( q!=NULL ) q->egroup=mystrdup(LATEXT(1));>> }
  666.             <<
  667.             if ( GenEClasseForRules && q!=NULL ) {
  668.                 e = newECnode;
  669.                 require(e!=NULL, "cannot allocate error class node");
  670.                 if ( q->egroup == NULL ) {a = q->str; a[0] = (char)toupper(a[0]);}
  671.                 else a = q->egroup;
  672.                 if ( Tnum( a ) == 0 )
  673.                 {
  674.                     e->tok = addTname( a );
  675.                     list_add(&eclasses, (char *)e);
  676.                     if ( q->egroup == NULL ) a[0] = (char)tolower(a[0]);
  677.                     /* refers to itself */
  678.                     list_add(&(e->elist), mystrdup(q->str));
  679.                 }
  680.                 else {
  681.                     warn(eMsg1("default errclass for '%s' would conflict with token/errclass/tokclass",a));
  682.                     if ( q->egroup == NULL ) a[0] = (char)tolower(a[0]);
  683.                     free((char *)e);
  684.                 }
  685.             }
  686.             >>
  687.             <<BlkLevel++;>>
  688.             ":" <<inAlt=1;>>
  689.             block[&toksrefd, &rulesrefd]
  690.             <<r = makeBlk($7,0);
  691.               CurRuleBlk = (Junction *)r.left;
  692.               CurRuleBlk->blockid = CurBlockID;
  693.               CurRuleBlk->jtype = RuleBlk;
  694.               if ( q!=NULL ) CurRuleBlk->rname = q->str;
  695.               CurRuleBlk->file = f;
  696.               CurRuleBlk->line = l;
  697.               CurRuleBlk->pdecl = pdecl;
  698.               CurRuleBlk->ret = ret;
  699.               CurRuleBlk->lock = makelocks();
  700.               CurRuleBlk->pred_lock = makelocks();
  701.               CurRuleBlk->tokrefs = toksrefd;
  702.               CurRuleBlk->rulerefs = rulesrefd;
  703.               p = newJunction();    /* add EndRule Node */
  704.               ((Junction *)r.right)->p1 = (Node *)p;
  705.               r.right = (Node *) p;
  706.               p->jtype = EndRule;
  707.               p->lock = makelocks();
  708.               p->pred_lock = makelocks();
  709.               CurRuleBlk->end = p;
  710.               if ( q!=NULL ) q->rulenum = NumRules;
  711.               $7 = r;
  712.             >>
  713.             <<--BlkLevel;>>
  714.             ";" <<inAlt=0;>>
  715.             {    Action
  716.                 <<    a = (char *) calloc(strlen(LATEXT(1))+1, sizeof(char));
  717.                     require(a!=NULL, "rule rule: cannot allocate error action");
  718.                     strcpy(a, LATEXT(1));
  719.                     CurRuleBlk->erraction = a;
  720.                 >>
  721.             }
  722.             (    exception_group > [eg]
  723.                 <<if ( eg!=NULL ) {
  724.                     list_add(&CurExGroups, (void *)eg);
  725.                     if ( eg->label=='\0' ) q->has_rule_exception = 1;
  726.                 }
  727.                 >>
  728.             )*
  729.             <<if ( q==NULL ) $0.left = NULL; else $0 = $7;>>
  730.             <<CurRuleNode = NULL;>>
  731.             <<CurRuleBlk->exceptions = CurExGroups;>>
  732.             <<CurRuleBlk->el_labels = CurElementLabels;>>
  733.         ;
  734.         <<CannotContinue=TRUE;>>
  735.  
  736. laction    :    <<char *a;>>
  737.             "#lexaction"
  738.             Action
  739.             <<
  740.             a = (char *) calloc(strlen(LATEXT(1))+1, sizeof(char));
  741.             require(a!=NULL, "rule laction: cannot allocate action");
  742.             strcpy(a, LATEXT(1));
  743.             list_add(&LexActions, a);
  744.             >>
  745.         ;
  746.         <<CannotContinue=TRUE;>>
  747.  
  748. aLexclass:    "#lexclass" TokenTerm <<lexclass(mystrdup(LATEXT(1)));>>
  749.         ;
  750.         <<CannotContinue=TRUE;>>
  751.  
  752. error    :    <<char *t=NULL; ECnode *e; int go=1; TermEntry *p;>>
  753.             "#errclass"
  754.             (<<;>>    TokenTerm  <<t=mystrdup(LATEXT(1));>>
  755.             |        QuotedTerm <<t=mystrdup(LATEXT(1));>>
  756.             )
  757.             <<e = newECnode;
  758.               require(e!=NULL, "cannot allocate error class node");
  759.               e->lexclass = CurrentLexClass;
  760.               if ( Tnum( (t=StripQuotes(t)) ) == 0 )
  761.               {
  762.                 if ( hash_get(Texpr, t) != NULL )
  763.                     warn(eMsg1("errclass name conflicts with regular expression  '%s'",t));
  764.                   e->tok = addTname( t );
  765.                 set_orel(e->tok, &imag_tokens);
  766.                 require((p=(TermEntry *)hash_get(Tname, t)) != NULL,
  767.                         "hash table mechanism is broken");
  768.                 p->classname = 1;    /* entry is errclass name, not token */
  769.                 list_add(&eclasses, (char *)e);
  770.               }
  771.               else
  772.               {
  773.                   warn(eMsg1("redefinition of errclass or conflict w/token or tokclass '%s'; ignored",t));
  774.                 free( (char *)e );
  775.                 go=0;
  776.               }
  777.             >>
  778.             "\{"
  779.                 ( NonTerminal <<if ( go ) t=mystrdup(LATEXT(1));>>
  780.                 | TokenTerm <<if ( go ) t=mystrdup(LATEXT(1));>>
  781.                 | QuotedTerm <<if ( go ) t=mystrdup(LATEXT(1));>>
  782.                 )
  783.                 <<if ( go ) list_add(&(e->elist), t);>>
  784.                 (
  785.                     ( NonTerminal <<if ( go ) t=mystrdup(LATEXT(1));>>
  786.                     | TokenTerm <<if ( go ) t=mystrdup(LATEXT(1));>>
  787.                     | QuotedTerm <<if ( go ) t=mystrdup(LATEXT(1));>>
  788.                     )
  789.                     <<if ( go ) list_add(&(e->elist), t);>>
  790.                 )*
  791.             "\}"
  792.         ;
  793.         <<CannotContinue=TRUE;>>
  794.  
  795. tclass    :    <<char *t=NULL; TCnode *e; int go=1,tok; TermEntry *p, *term;>>
  796.             "#tokclass" TokenTerm <<t=mystrdup(LATEXT(1));>>
  797.             <<e = newTCnode;
  798.               require(e!=NULL, "cannot allocate token class node");
  799.               e->lexclass = CurrentLexClass;
  800.               if ( Tnum( t ) == 0 )
  801.               {
  802.                   e->tok = addTname( t );
  803.                 set_orel(e->tok, &imag_tokens);
  804.                 set_orel(e->tok, &tokclasses);
  805.                 require((p=(TermEntry *)hash_get(Tname, t)) != NULL,
  806.                         "hash table mechanism is broken");
  807.                 p->classname = 1;    /* entry is class name, not token */
  808.                 p->tclass = e;        /* save ptr to this tclass def */
  809.                 list_add(&tclasses, (char *)e);
  810.               }
  811.               else
  812.               {
  813.                   warn(eMsg1("redefinition of tokclass or conflict w/token '%s'; ignored",t));
  814.                 free( (char *)e );
  815.                 go=0;
  816.               }
  817.             >>
  818.             "\{"
  819.                 (
  820.                 ( TokenTerm
  821.                   <<if ( go ) {
  822.                     term = (TermEntry *) hash_get(Tname, LATEXT(1));
  823.                     if ( term==NULL && UserDefdTokens ) {
  824.                         err("implicit token definition not allowed with #tokdefs");
  825.                         go = 0;
  826.                     }
  827.                     else {t=mystrdup(LATEXT(1)); tok=addTname(LATEXT(1));}
  828.                     }>>
  829.                 | QuotedTerm
  830.                   <<if ( go ) {
  831.                     term = (TermEntry *) hash_get(Texpr, LATEXT(1));
  832.                     if ( term==NULL && UserDefdTokens ) {
  833.                         err("implicit token definition not allowed with #tokdefs");
  834.                         go = 0;
  835.                     }
  836.                     else {t=mystrdup(LATEXT(1)); tok=addTexpr(LATEXT(1));}
  837.                     }>>
  838.                 )
  839.                 <<if ( go ) list_add(&(e->tlist), t);>>
  840.                 )*
  841.             "\}"
  842.         ;
  843.         <<CannotContinue=TRUE;>>
  844.  
  845. token    :    <<char *t=NULL, *e=NULL, *a=NULL; int tnum=0;>>
  846.             "#token"
  847.             {    TokenTerm  <<t=mystrdup(LATEXT(1));>>
  848.                 {    "=" "[0-9]+"        /* define the token type number */
  849.                     <<tnum = atoi(LATEXT(1));>>
  850.                 }
  851.             }
  852.             { QuotedTerm <<e=mystrdup(LATEXT(1));>> }
  853.             {    Action
  854.                 <<
  855.                     a = (char *) calloc(strlen(LATEXT(1))+1, sizeof(char));
  856.                     require(a!=NULL, "rule token: cannot allocate action");
  857.                     strcpy(a, LATEXT(1));
  858.                 >>
  859.             }
  860.             <<chkToken(t, e, a, tnum);>>
  861.         ;
  862.         <<CannotContinue=TRUE;>>
  863.  
  864. block[set *toksrefd, set *rulesrefd]
  865.         :    <<
  866.             Graph g, b;
  867.             set saveblah;
  868.             int saveinalt = inAlt;
  869.             ExceptionGroup *eg;
  870.             *$toksrefd = empty;
  871.             *$rulesrefd = empty;
  872.             set_clr(AST_nodes_refd_in_actions);
  873.             CurBlockID++;
  874.             CurAltNum = 1;
  875.             saveblah = attribsRefdFromAction;
  876.             attribsRefdFromAction = empty;
  877.             >>
  878.             alt[toksrefd,rulesrefd]        <<b = g = $1;>>
  879.             <<
  880.             if ( ((Junction *)g.left)->p1->ntype == nAction )
  881.             {
  882.                 if ( !((ActionNode *)(((Junction *)g.left)->p1))->is_predicate )
  883.                 {
  884.                     ((ActionNode *)(((Junction *)g.left)->p1))->init_action = TRUE;
  885.                 }
  886.             }
  887.             ((Junction *)g.left)->blockid = CurBlockID;
  888.             >>
  889.  
  890.             (    exception_group > [eg]
  891.                 <<
  892.                 if ( eg!=NULL ) {
  893.                     eg->altID = makeAltID(CurBlockID,CurAltNum);
  894.                     CurAltStart->exception_label = eg->altID;
  895.                     list_add(&CurExGroups, (void *)eg);
  896.                 }
  897.                 >>
  898.             )*
  899.             <<CurAltNum++;>>
  900.  
  901.             (    "\|" <<inAlt=1;>>
  902.                 alt[toksrefd,rulesrefd]        <<g = Or(g, $2);>>
  903.                 <<
  904.                 ((Junction *)g.left)->blockid = CurBlockID;
  905.                 >>
  906.  
  907.                 (    exception_group > [eg]
  908.                     <<
  909.                     if ( eg!=NULL ) {
  910.                         eg->altID = makeAltID(CurBlockID,CurAltNum);
  911.                         CurAltStart->exception_label = eg->altID;
  912.                         list_add(&CurExGroups, (void *)eg);
  913.                     }
  914.                     >>
  915.                 )*
  916.  
  917.                 <<CurAltNum++;>>
  918.  
  919.             )*
  920.             <<$0 = b;>>
  921.             <<attribsRefdFromAction = saveblah; inAlt = saveinalt;>>
  922.         ;
  923.         <<CannotContinue=TRUE;>>
  924.  
  925. alt[set *toksrefd, set *rulesrefd]
  926.         :    <<int n=0,ne=0; Graph g; int e_num=0, not=0; Node *node; set elems, dif;
  927.             int first_on_line = 1, use_def_MT_handler = 0;
  928.             g.left=NULL; g.right=NULL;
  929.             CurAltStart = NULL;
  930.             elems = empty;
  931.             inAlt = 1;
  932.             >>
  933.             {    "\@"    /* handle MismatchedToken signals with default handler */
  934.                 <<use_def_MT_handler = 1;>>
  935.             }
  936.             (    <<int tok;>>
  937.                 { <<not=0;>> "\~" <<not=1;>> }
  938.                 element[not, first_on_line, use_def_MT_handler] > [node]
  939.                 <<if ( node!=NULL && node->ntype!=nAction ) first_on_line = 0;>>
  940.                 <<
  941.                 if ( $2.left!=NULL ) {
  942.                     g = Cat(g, $2);
  943.                     n++;
  944.                     if ( node!=NULL ) {
  945.                         if ( node->ntype!=nAction ) e_num++;
  946.                         /* record record number of all rule and token refs */
  947.                         if ( node->ntype==nToken ) {
  948.                             TokNode *tk = (TokNode *)((Junction *)$2.left)->p1;
  949.                             tk->elnum = e_num;
  950.                             set_orel(e_num, &elems);
  951.                         }
  952.                         else if ( node->ntype==nRuleRef ) {
  953.                             RuleRefNode *rn = (RuleRefNode *)((Junction *)$2.left)->p1;
  954.                             rn->elnum = e_num;
  955.                             set_orel(e_num, $rulesrefd);
  956.                         }
  957.                     }
  958.                 }
  959.                 >>
  960.             )*
  961.             <<if ( n == 0 ) g = emptyAlt();
  962.               $0 = g;
  963.               /* We want to reduce number of LT(i) calls and the number of
  964.                * local attribute variables in C++ mode (for moment, later we'll
  965.                * do for C also).  However, if trees are being built, they
  966.                * require most of the attrib variables to create the tree nodes
  967.                * with; therefore, we gen a token ptr for each token ref in C++
  968.                */
  969.               if ( GenCC && !GenAST )
  970.                  set_orin($toksrefd, set_and(elems, attribsRefdFromAction));
  971.               else set_orin($toksrefd, elems);
  972.               if ( GenCC ) {
  973.                 dif = set_dif(attribsRefdFromAction, elems);
  974.                   if ( set_deg(dif)>0 )
  975.                     err("one or more $i in action(s) refer to non-token elements");
  976.                 set_free(dif);
  977.               }
  978.               set_free(elems);
  979.               set_free(attribsRefdFromAction);
  980.               inAlt = 0;
  981.                >>
  982.         ;
  983.         <<CannotContinue=TRUE;>>
  984.  
  985. element_label > [LabelEntry *label]
  986.     :    <<TermEntry *t=NULL; LabelEntry *l=NULL; RuleEntry *r=NULL; char *lab;>>
  987.         LABEL    <<lab = mystrdup(LATEXT(1));>>
  988.         <<
  989.         UsedNewStyleLabel = 1;
  990.         if ( UsedOldStyleAttrib ) err("cannot mix with new-style labels with old-style $i");
  991.         t = (TermEntry *) hash_get(Tname, lab);
  992.         if ( t==NULL ) t = (TermEntry *) hash_get(Texpr, lab);
  993.         if ( t==NULL ) r = (RuleEntry *) hash_get(Rname, lab);
  994.         if ( t!=NULL ) {
  995.             err(eMsg1("label definition clashes with token/tokclass definition: '%s'", lab));
  996.             $label = NULL;
  997.         }
  998.         else if ( r!=NULL ) {
  999.             err(eMsg1("label definition clashes with rule definition: '%s'", lab));
  1000.             $label = NULL;
  1001.         }
  1002.         else {
  1003.             /* we don't clash with anybody else */
  1004.             l = (LabelEntry *) hash_get(Elabel, lab);
  1005.              if ( l==NULL ) {    /* ok to add new element label */
  1006.                 l = (LabelEntry *)hash_add(Elabel,
  1007.                                            lab,
  1008.                                            (Entry *)newLabelEntry(lab));
  1009.                 /* add to list of element labels for this rule */
  1010.                 list_add(&CurElementLabels, (void *)lab);
  1011.                 $label = l;
  1012.             }
  1013.             else {
  1014.                 err(eMsg1("label definitions must be unique per rule: '%s'", lab));
  1015.                 $label = NULL;
  1016.             }
  1017.         }
  1018.         >>
  1019.         ":"
  1020.     ;
  1021.  
  1022. element[int not, int first_on_line, int use_def_MT_handler] > [Node *node]
  1023.         : <<
  1024.           int local_use_def_MT_handler=0;
  1025.           ActionNode *act;
  1026.           RuleRefNode *rr;
  1027.           set toksrefd, rulesrefd;
  1028.           TermEntry *term;
  1029.           TokNode *p=NULL; RuleRefNode *q; int approx=0;
  1030.           LabelEntry *label=NULL;
  1031.           $node = NULL;
  1032.           >>
  1033.           {element_label>[label]}
  1034.           ( TokenTerm
  1035.             <<
  1036.             term = (TermEntry *) hash_get(Tname, LATEXT(1));
  1037.             if ( term==NULL && UserDefdTokens ) {
  1038.                 err("implicit token definition not allowed with #tokdefs");
  1039.                 $$.left = $$.right = NULL;
  1040.             }
  1041.             else {
  1042.                 $$ = buildToken(LATEXT(1));
  1043.                 p=((TokNode *)((Junction *)$$.left)->p1);
  1044.                 term = (TermEntry *) hash_get(Tname, LATEXT(1));
  1045.                 require( term!= NULL, "hash table mechanism is broken");
  1046.                 p->tclass = term->tclass;
  1047.                 p->complement = $not;
  1048.                 if ( label!=NULL ) {
  1049.                     p->el_label = label->str;
  1050.                     label->elem = (Node *)p;
  1051.                 }
  1052.             }
  1053.             >>
  1054.             {    ".."
  1055.                 (    QuotedTerm
  1056.                     <<if ( p!=NULL ) setUpperRange(p, LATEXT(1));>>
  1057.                 |    TokenTerm
  1058.                     <<if ( p!=NULL ) setUpperRange(p, LATEXT(1));>>
  1059.                 )
  1060.             }
  1061.             <<
  1062.             if ( p!=NULL && (p->upper_range!=0 || p->tclass || $not) )
  1063.                 list_add(&MetaTokenNodes, (void *)p);
  1064.             >>
  1065.             (    "^"    <<if ( p!=NULL ) p->astnode=ASTroot;>>
  1066.             |        <<if ( p!=NULL ) p->astnode=ASTchild;>>
  1067.             |    "!" <<if ( p!=NULL ) p->astnode=ASTexclude;>>
  1068.             )
  1069.             { "\@" <<local_use_def_MT_handler = 1;>> }
  1070.             <<
  1071.             if ( p!=NULL && $first_on_line ) {
  1072.                 CurAltStart = (Junction *)$$.left;
  1073.                 p->altstart = CurAltStart;
  1074.             }
  1075.                if ( p!=NULL )
  1076.                 p->use_def_MT_handler = $use_def_MT_handler || local_use_def_MT_handler;
  1077.             $node = (Node *)p;
  1078.             >>
  1079.           | QuotedTerm
  1080.             <<
  1081.             term = (TermEntry *) hash_get(Texpr, LATEXT(1));
  1082.             if ( term==NULL && UserDefdTokens ) {
  1083.                 err("implicit token definition not allowed with #tokdefs");
  1084.                 $$.left = $$.right = NULL;
  1085.             }
  1086.             else {
  1087.                 $$ = buildToken(LATEXT(1)); p=((TokNode *)((Junction *)$$.left)->p1);
  1088.                 p->complement = $not;
  1089.                 if ( label!=NULL ) {
  1090.                     p->el_label = label->str;
  1091.                        label->elem = (Node *)p;
  1092.                 }
  1093.             }
  1094.             >>
  1095.             {    ".."
  1096.                 (    QuotedTerm
  1097.                     <<if ( p!=NULL ) setUpperRange(p, LATEXT(1));>>
  1098.                 |    TokenTerm
  1099.                     <<if ( p!=NULL ) setUpperRange(p, LATEXT(1));>>
  1100.                 )
  1101.             }
  1102.             (    "^"    <<if ( p!=NULL ) p->astnode=ASTroot;>>
  1103.             |        <<if ( p!=NULL ) p->astnode=ASTchild;>>
  1104.             |    "!" <<if ( p!=NULL ) p->astnode=ASTexclude;>>
  1105.             )
  1106.             { "\@" <<local_use_def_MT_handler = 1;>> }
  1107.             <<
  1108.             if ( p!=NULL && (p->upper_range!=0 || p->tclass || $not) )
  1109.                 list_add(&MetaTokenNodes, (void *)p);
  1110.             >>
  1111.             <<
  1112.             if ( $first_on_line ) {
  1113.                 CurAltStart = (Junction *)$$.left;
  1114.                 p->altstart = CurAltStart;
  1115.             }
  1116.                if ( p!=NULL )
  1117.                 p->use_def_MT_handler = $use_def_MT_handler || local_use_def_MT_handler;
  1118.             $node = (Node *)p;
  1119.             >>
  1120.  
  1121.           | <<if ( $not ) warn("~ WILDCARD is an undefined operation (implies 'nothing')");>>
  1122.             "."
  1123.             <<$$ = buildWildCard(LATEXT(1)); p=((TokNode *)((Junction *)$$.left)->p1);>>
  1124.             (    "^"    <<p->astnode=ASTroot;>>
  1125.             |        <<p->astnode=ASTchild;>>
  1126.             |    "!" <<p->astnode=ASTexclude;>>
  1127.             )
  1128.             <<list_add(&MetaTokenNodes, (void *)p);>>
  1129.             <<
  1130.             if ( $first_on_line ) {
  1131.                 CurAltStart = (Junction *)$$.left;
  1132.                 p->altstart = CurAltStart;
  1133.                 if ( label!=NULL ) {
  1134.                     p->el_label = label->str;
  1135.                     label->elem = (Node *)p;
  1136.                 }
  1137.             }
  1138.             $node = (Node *)p;
  1139.             >>
  1140.  
  1141.           | <<if ( $not ) warn("~ NONTERMINAL is an undefined operation");>>
  1142.             NonTerminal
  1143.             <<$$ = buildRuleRef(LATEXT(1));>>
  1144.             { "!" <<q = (RuleRefNode *) ((Junction *)$$.left)->p1;
  1145.                     q->astnode=ASTexclude;>>
  1146.             }
  1147.             {    {"\<"}
  1148.                 PassAction <<addParm(((Junction *)$$.left)->p1, LATEXT(1));>>
  1149.             }
  1150.             <<rr=(RuleRefNode *) ((Junction *)$$.left)->p1;>>
  1151.             {    <<char *a;>>
  1152.                 "\>"
  1153.                 PassAction
  1154.                 <<
  1155.                     a = (char *) calloc(strlen(LATEXT(1))+1, sizeof(char));
  1156.                     require(a!=NULL, "rule element: cannot allocate assignment");
  1157.                     strcpy(a, LATEXT(1));
  1158.                     rr->assign = a;
  1159.                 >>
  1160.             }
  1161.             <<
  1162.             if ( label!=NULL ) {
  1163.                 rr->el_label = label->str;
  1164.                 label->elem = (Node *)rr;
  1165.             }
  1166.             if ( $first_on_line ) {
  1167.                 CurAltStart = (Junction *)$$.left;
  1168.                 ((RuleRefNode *)((Junction *)$$.left)->p1)->altstart = CurAltStart;
  1169.             }
  1170.             $node = (Node *)rr;
  1171.             >>
  1172.           )
  1173.  
  1174.         |    <<if ( $not )    warn("~ ACTION is an undefined operation");>>
  1175.             Action <<$0 = buildAction(LATEXT(1),action_file,action_line, 0);>>
  1176.             <<if ( $first_on_line ) CurAltStart = (Junction *)$0.left;>>
  1177.             <<$node = (Node *) ((Junction *)$0.left)->p1;>>
  1178.  
  1179.         |    <<if ( $not )    warn("~ SEMANTIC-PREDICATE is an undefined operation");>>
  1180.             Pred   <<$0 = buildAction(LATEXT(1),action_file,action_line, 1);>>
  1181.             <<act = (ActionNode *) ((Junction *)$0.left)->p1;>>
  1182.             {    <<char *a;>>
  1183.                 PassAction
  1184.                 <<
  1185.                 a = (char *) calloc(strlen(LATEXT(1))+1, sizeof(char));
  1186.                 require(a!=NULL, "rule element: cannot allocate predicate fail action");
  1187.                 strcpy(a, LATEXT(1));
  1188.                 act->pred_fail = a;
  1189.                 >>
  1190.             }
  1191.             <<if ( $first_on_line ) CurAltStart = (Junction *)$0.left;>>
  1192.             <<$node = (Node *)act;>>
  1193.  
  1194.         |    <<if ( $not )    warn("~ BLOCK is an undefined operation");>>
  1195.             <<BlkLevel++;>>
  1196.             {    "#pragma"
  1197.                 (    "approx" <<approx=LL_k;>>
  1198.                 |    "LL(1)"  <<approx = 1;>>
  1199.                 |    "LL(2)"  <<approx = 2;>>
  1200.                 )
  1201.             }
  1202.             (    "\(" block[&toksrefd,&rulesrefd]
  1203.                                 <<$$ = $2; --BlkLevel;>> "\)"
  1204.                 (    "\*"        <<$$ = makeLoop($$,approx);>>
  1205.                 |    "\+"        <<$$ = makePlus($$,approx);>>
  1206.                 |    "?"            <<$$ = makeBlk($$,approx);
  1207.                                   FoundGuessBlk = 1;
  1208.                                   ((Junction *) ((Junction *)$$.left)->p1)->guess=1;
  1209.                                   if ( !$first_on_line ) {
  1210.                                     err("(...)? predicate must be first element of production");
  1211.                                   }
  1212.                                 >>
  1213.                 |                <<$$ = makeBlk($$,approx);>>
  1214.                 )
  1215.                 <<
  1216.                 ((Junction *)((Junction *)$$.left)->p1)->blockid = CurBlockID;
  1217.                 ((Junction *)((Junction *)$$.left)->p1)->tokrefs = toksrefd;
  1218.                 ((Junction *)((Junction *)$$.left)->p1)->rulerefs = rulesrefd;
  1219.                 >>
  1220.                 <<if ( $first_on_line ) 
  1221.                     CurAltStart = (Junction *)((Junction *)((Junction *)$$.left)->p1);
  1222.                 >>
  1223.                 <<$node = (Node *) ((Junction *)$$.left)->p1;>>
  1224.  
  1225.             |    "\{"    block[&toksrefd,&rulesrefd]
  1226.                         <<$$ = makeOpt($2,approx); --BlkLevel;>>
  1227.                 "\}"
  1228.                 <<
  1229.                 ((Junction *)((Junction *)$$.left)->p1)->blockid = CurBlockID;
  1230.                 ((Junction *)((Junction *)$$.left)->p1)->tokrefs = toksrefd;
  1231.                 ((Junction *)((Junction *)$$.left)->p1)->rulerefs = rulesrefd;
  1232.                 >>
  1233.                 <<if ( $first_on_line )
  1234.                     CurAltStart = (Junction *) ((Junction *)((Junction *)$$.left)->p1);
  1235.                 >>
  1236.                 <<$node = (Node *) ((Junction *)$$.left)->p1;>>
  1237.  
  1238.             )
  1239.  
  1240. /* Error catching alternatives */
  1241.         |    "\*"    <<warn("don't you want a ')' with that '*'?"); CannotContinue=TRUE;>>
  1242.         |    "\+"    <<warn("don't you want a ')' with that '+'?"); CannotContinue=TRUE;>>
  1243.         |    "\>"    <<warn("'>' can only appear after a nonterminal"); CannotContinue=TRUE;>>
  1244.         |    PassAction <<warn("[...] out of context 'rule > [...]'");
  1245.                          CannotContinue=TRUE;>>
  1246.         ;
  1247.         <<CannotContinue=TRUE;>>
  1248.  
  1249. default_exception_handler
  1250.     :    exception_group > [DefaultExGroup]
  1251.     ;
  1252.  
  1253. exception_group > [ExceptionGroup *eg]
  1254.     :    <<ExceptionHandler *h; LabelEntry *label=NULL; FoundException = 1;>>
  1255.         "exception"     <<$eg = (ExceptionGroup *)calloc(1, sizeof(ExceptionGroup));>>
  1256.         {    <<char *p;>>
  1257.             PassAction        /* did they attach a label? */
  1258.             <<
  1259.             p = LATEXT(1)+1;
  1260.             p[strlen(p)-1] = '\0';        /* kill trailing space */
  1261.             label = (LabelEntry *) hash_get(Elabel, LATEXT(1)+1);
  1262.             if ( label==NULL )
  1263.             {
  1264.                 err(eMsg1("unknown label in exception handler: '%s'", LATEXT(1)+1));
  1265.             }
  1266.             >>
  1267.         }
  1268.         (    exception_handler > [h]
  1269.             <<list_add(&($eg->handlers), (void *)h);>>
  1270.         )*
  1271.         {    "default" ":" Action
  1272.             <<{
  1273.             ExceptionHandler *eh = (ExceptionHandler *)
  1274.                 calloc(1, sizeof(ExceptionHandler));
  1275.             char *a = (char *) calloc(strlen(LATEXT(1))+1, sizeof(char));
  1276.             require(eh!=NULL, "exception: cannot allocate handler");
  1277.             require(a!=NULL, "exception: cannot allocate action");
  1278.             strcpy(a, LATEXT(1));
  1279.             eh->action = a;
  1280.             eh->signalname = (char *) calloc(strlen("default")+1, sizeof(char));
  1281.             require(eh->signalname!=NULL, "exception: cannot allocate sig name");
  1282.             strcpy(eh->signalname, "default");
  1283.             list_add(&($eg->handlers), (void *)eh);
  1284.             }>>
  1285.         }
  1286.         <<
  1287.         if ( label!=NULL ) {
  1288.             /* Record ex group in sym tab for this label */
  1289.             if ( label->ex_group!=NULL ) {
  1290.                 err(eMsg1("duplicate exception handler for label '%s'",label->str));
  1291.             }
  1292.             else {
  1293.                 label->ex_group = $eg;
  1294.                 /* Label the exception group itself */
  1295.                 $eg->label = label->str;
  1296.                 /* Make the labelled element pt to the exception also */
  1297.                 switch ( label->elem->ntype ) {
  1298.                     case nRuleRef :
  1299.                         {
  1300.                         RuleRefNode *r = (RuleRefNode *)label->elem;
  1301.                         r->ex_group = $eg;
  1302.                         break;
  1303.                         }
  1304.                     case nToken :
  1305.                         {
  1306.                         TokNode *t = (TokNode *)label->elem;
  1307.                         t->ex_group = $eg;
  1308.                         break;
  1309.                         }
  1310.                 }
  1311.             }
  1312.             /* You may want to remove this exc from the rule list
  1313.              * and handle at the labeled element site.
  1314.              */
  1315.             $eg = NULL;
  1316.         }
  1317.         >>
  1318.     ;
  1319.     <<CannotContinue=TRUE;>>
  1320.  
  1321. exception_handler > [ExceptionHandler *eh]
  1322.     :    <<char *a;>>
  1323.         "catch"
  1324.         <<
  1325.         $eh = (ExceptionHandler *)calloc(1, sizeof(ExceptionHandler));
  1326.         require($eh!=NULL, "exception: cannot allocate handler");
  1327.         >>
  1328.         (    NonTerminal
  1329.             <<
  1330.             $eh->signalname = (char *) calloc(strlen(LATEXT(1))+1, sizeof(char));
  1331.             require($eh->signalname!=NULL, "exception: cannot allocate sig name");
  1332.             strcpy($eh->signalname, LATEXT(1));
  1333.             >>
  1334.         |    TokenTerm
  1335.             <<
  1336.             $eh->signalname = (char *) calloc(strlen(LATEXT(1))+1, sizeof(char));
  1337.             require($eh->signalname!=NULL, "exception: cannot allocate sig name");
  1338.             strcpy($eh->signalname, LATEXT(1));
  1339.             >>
  1340.         )
  1341.         ":"
  1342.         {    <<$eh->action = NULL;>>
  1343.             Action
  1344.             <<
  1345.             $eh->action = (char *) calloc(strlen(LATEXT(1))+1, sizeof(char));
  1346.             require($eh->action!=NULL, "exception: cannot allocate action");
  1347.             strcpy($eh->action, LATEXT(1));
  1348.             >>
  1349.         }
  1350.     ;
  1351.     <<CannotContinue=TRUE;>>
  1352.  
  1353. #token NonTerminal        "[a-z] [A-Za-z0-9_]*"
  1354.                             <<
  1355.                             while ( zzchar==' ' || zzchar=='\t' ) {
  1356.                                 zzadvance();
  1357.                             }
  1358.                             if ( zzchar == ':' && inAlt ) NLA = LABEL;
  1359.                             >>
  1360. #token TokenTerm        "[A-Z] [A-Za-z0-9_]*"
  1361.                             <<
  1362.                             while ( zzchar==' ' || zzchar=='\t' ) {
  1363.                                 zzadvance();
  1364.                             }
  1365.                             if ( zzchar == ':' && inAlt ) NLA = LABEL;
  1366.                             >>
  1367. #token "#[A-Za-z0-9_]*"    <<warn(eMsg1("unknown meta-op: %s",LATEXT(1))); zzskip(); >>
  1368.  
  1369. #lexclass PARSE_ENUM_FILE
  1370.  
  1371. #token "[\t\ ]+"            << zzskip(); >>                /* Ignore White */
  1372. #token "[\n\r]"                << zzline++; zzskip(); >>    /* Track Line # */
  1373. #token "//"                    << zzmode(TOK_DEF_CPP_COMMENTS); zzmore(); >>
  1374. #token "/\*"                << zzmode(TOK_DEF_COMMENTS); zzskip(); >>
  1375. #token "#ifdef"                << zzmode(TOK_DEF_CPP_COMMENTS); zzskip(); >>
  1376. #token "#if"                << zzmode(TOK_DEF_CPP_COMMENTS); zzskip(); >>
  1377. #token "#ifndef"            << ; >>
  1378. #token "#else"                << zzmode(TOK_DEF_CPP_COMMENTS); zzskip(); >>
  1379. #token "#endif"                << zzmode(TOK_DEF_CPP_COMMENTS); zzskip(); >>
  1380. #token "#undef"                << zzmode(TOK_DEF_CPP_COMMENTS); zzskip(); >>
  1381. #token "#import"            << zzmode(TOK_DEF_CPP_COMMENTS); zzskip(); >>
  1382. #token "@"                    << ; >>
  1383.  
  1384. enum_file[char *fname]
  1385.     :    {    "#ifndef" ID
  1386.             {    "#define" ID /* ignore if it smells like a gate */
  1387.                 /* First #define after the first #ifndef (if any) is ignored */
  1388.             }
  1389.         }
  1390.         (    ( enum_def[$fname] )+
  1391.         |    defines[$fname]
  1392.         )
  1393.     |
  1394.     ;
  1395.  
  1396. defines[char *fname]
  1397.     :    <<int v,maxt= -1; char *t;>>
  1398.         (
  1399.             "#define" ID
  1400.             <<t = mystrdup(LATEXT(1));>>
  1401.             INT
  1402.             <<
  1403.             v = atoi(LATEXT(1));
  1404. /*            fprintf(stderr, "#token %s=%d\n", t, v);*/
  1405.             TokenNum = v;
  1406.             if ( v>maxt ) maxt=v;
  1407.             if ( Tnum( t ) == 0 ) addForcedTname( t, v );
  1408.             else {
  1409.                 warnFL(eMsg1("redefinition of token %s; ignored",t),$fname,zzline);
  1410.             }
  1411.             >>
  1412.         )+
  1413.         <<TokenNum = maxt + 1;>>
  1414.     ;
  1415.  
  1416. enum_def[char *fname]
  1417.     :    <<int v= 0; char *t;>>
  1418.         "enum" ID
  1419.         "\{"
  1420.             ID
  1421.             <<t = mystrdup(LATEXT(1));>>
  1422.             (    "=" INT    <<v=atoi(LATEXT(1));>>
  1423.             |            <<v++;>>
  1424.             )
  1425.             <<
  1426. /*            fprintf(stderr, "#token %s=%d\n", t, v);*/
  1427.             TokenNum = v;
  1428.             if ( Tnum( t ) == 0 ) addForcedTname( t, v );
  1429.             else {
  1430.                 warnFL(eMsg1("redefinition of token %s; ignored",t),$fname,zzline);
  1431.             }
  1432.             >>
  1433.             (    ","
  1434.                 {    ID
  1435.                     <<t = mystrdup(LATEXT(1));>>
  1436.                     (    "=" INT    <<v=atoi(LATEXT(1));>>
  1437.                     |            <<v++;>>
  1438.                     )
  1439.                     <<
  1440. /*                    fprintf(stderr, "#token %s=%d\n", t, v);*/
  1441.                     TokenNum = v;
  1442.                     if ( Tnum( t ) == 0 ) addForcedTname( t, v );
  1443.                     else {
  1444.                         warnFL(eMsg1("redefinition of token %s; ignored",t),$fname,zzline);
  1445.                     }
  1446.                     >>
  1447.                 }
  1448.             )*
  1449.         "\}"
  1450.         ";"
  1451.         <<TokenNum++;>>
  1452.     ;
  1453.  
  1454. #token INT    "[0-9]+"
  1455. #token ID    "[a-zA-Z_][_a-zA-Z0-9]*"
  1456.  
  1457. #lexclass START
  1458.  
  1459. <<
  1460. /* semantics of #token */
  1461. static void
  1462. #ifdef __STDC__
  1463. chkToken(char *t, char *e, char *a, int tnum)
  1464. #else
  1465. chkToken(t,e,a,tnum)
  1466. char *t, *e, *a;
  1467. int tnum;
  1468. #endif
  1469. {
  1470.     TermEntry *p;
  1471.  
  1472.     /* check to see that they don't try to redefine a token as a token class */
  1473.     if ( t!=NULL ) {
  1474.         p = (TermEntry *) hash_get(Tname, t);
  1475.         if ( p!=NULL && p->classname ) {
  1476.             err(eMsg1("redefinition of #tokclass '%s' to #token not allowed; ignored",t));
  1477.             if ( a!=NULL ) free((char *)a);
  1478.             return;
  1479.         }
  1480.     }
  1481.  
  1482.     if ( t==NULL && e==NULL ) {            /* none found */
  1483.         err("#token requires at least token name or rexpr");
  1484.     }
  1485.     else if ( t!=NULL && e!=NULL ) {    /* both found */
  1486.         if ( UserDefdTokens ) {            /* if #tokdefs, must not define new */
  1487.             p = (TermEntry *) hash_get(Tname, t);
  1488.             if ( p==NULL ) {
  1489.                 err(eMsg1("#token definition '%s' not allowed with #tokdefs; ignored",t));
  1490.                 return;
  1491.             }
  1492.         }
  1493.         Tklink(t, e);
  1494.         if ( a!=NULL ) {
  1495.             if ( hasAction(e) ) {
  1496.                 err(eMsg1("redefinition of action for %s; ignored",e));
  1497.             }
  1498.             else setHasAction(e, a);
  1499.         }
  1500.     }
  1501.     else if ( t!=NULL ) {                /* only one found */
  1502.         if ( UserDefdTokens ) {
  1503.             err(eMsg1("#token definition '%s' not allowed with #tokdefs; ignored",t));
  1504.             return;
  1505.         }
  1506.         if ( Tnum( t ) == 0 ) addTname( t );
  1507.         else {
  1508.             err(eMsg1("redefinition of token %s; ignored",t));
  1509.         }
  1510.         if ( a!=NULL ) {
  1511.             err(eMsg1("action cannot be attached to a token name (%s); ignored",t));
  1512.             free((char *)a);
  1513.         }
  1514.     }
  1515.     else if ( e!=NULL ) {
  1516.         if ( Tnum( e ) == 0 ) addTexpr( e );
  1517.         else {
  1518.             if ( hasAction(e) ) {
  1519.                 err(eMsg1("redefinition of action for expr %s; ignored",e));
  1520.             }
  1521.             else if ( a==NULL ) {
  1522.                 err(eMsg1("redefinition of expr %s; ignored",e));
  1523.             }
  1524.         }
  1525.         if ( a!=NULL ) setHasAction(e, a);
  1526.     }
  1527.  
  1528.     /* if a token type number was specified, then add the token ID and 'tnum'
  1529.      * pair to the ForcedTokens list.  (only applies if an id was given)
  1530.      */
  1531.     if ( t!=NULL && tnum>0 )
  1532.     {
  1533.         if ( set_el(tnum, reserved_positions) )
  1534.         {
  1535.             err(eMsgd("a token has already been forced to token number %d; ignored", tnum));
  1536.         }
  1537.         else
  1538.         {
  1539.             list_add(&ForcedTokens, newForcedToken(t,tnum));
  1540.             set_orel(tnum, &reserved_positions);
  1541.         }
  1542.     }
  1543. }
  1544. >>
  1545.  
  1546. <<
  1547. /* ANTLR-specific syntax error message generator
  1548.  * (define USER_ZZSYN when compiling so don't get 2 definitions)
  1549.  */
  1550. void
  1551. #ifdef __STDC__
  1552. zzsyn(char *text, int tok, char *egroup, SetWordType *eset, int etok,  
  1553. int k, char *bad_text)
  1554. #else
  1555. zzsyn(text, tok, egroup, eset, etok, k, bad_text)
  1556. char *text, *egroup, *bad_text;
  1557. int tok;
  1558. int etok;
  1559. int k;
  1560. SetWordType *eset;
  1561. #endif
  1562. {
  1563.     fprintf(stderr, ErrHdr, FileStr[CurFile]!=NULL?FileStr[CurFile]:"stdin", zzline);
  1564.     fprintf(stderr, " syntax error at \"%s\"", (tok==zzEOF_TOKEN)?"EOF":text);
  1565.     if ( !etok && !eset ) {fprintf(stderr, "\n"); return;}
  1566.     if ( k==1 ) fprintf(stderr, " missing");
  1567.     else
  1568.     {
  1569.         fprintf(stderr, "; \"%s\" not", bad_text);
  1570.         if ( zzset_deg(eset)>1 ) fprintf(stderr, " in");
  1571.     }
  1572.     if ( zzset_deg(eset)>0 ) zzedecode(eset);
  1573.     else fprintf(stderr, " %s", zztokens[etok]);
  1574.     if ( strlen(egroup) > 0 ) fprintf(stderr, " in %s", egroup);
  1575.     fprintf(stderr, "\n");
  1576. }
  1577. >>
  1578.